﻿namespace Turnable.Functional
{
    public struct NoneType { }
    public struct ErrorType
    {
        public Exception Error { get; init; }
    }

    public static partial class F
    {
        public static Maybe<T> Some<T>(T value) => new Maybe<T>(value);
        public static NoneType None => default;
    }

    public struct Maybe<T>
    {
        readonly T? value;
        readonly bool isSome;

        internal Maybe(T value, bool isError = false)
        {
            this.value = value ?? throw new ArgumentNullException();
            this.isSome = true;
        }

        public static implicit operator Maybe<T>(NoneType _) => default;
        public static implicit operator Maybe<T>(T value) => value is null ? F.None : F.Some(value);
        public R Match<R>(Func<R> None, Func<T, R> Some) => isSome ? Some(value!) : None();
        public void Match(Action None, Action<T> Some)
        {
            if (isSome)
            {
                Some(value!);
            }
            else
            {
                None();
            }
        }
    }
}
